/**
 * HudManager.java
 *
 * Roslan's Remake of MOO in 3D using Ardor3D
 * (C) 2011 Roslan Amir. All rights reserved.
 */

package com.roslan.games.moo3d.ui.hud;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ardor3d.extension.ui.UILabel;
import com.ardor3d.extension.ui.border.SolidBorder;
import com.ardor3d.extension.ui.border.UIBorder;
import com.ardor3d.extension.ui.text.StyleConstants;
import com.ardor3d.extension.ui.util.Alignment;
import com.ardor3d.extension.ui.util.Insets;
import com.ardor3d.math.ColorRGBA;
import com.roslan.games.moo3d.Base;
import com.roslan.games.moo3d.GameData;
import com.roslan.games.moo3d.Main;
import com.roslan.games.moo3d.data.Star;
import com.roslan.games.moo3d.spatial.StarNode;

/**
 * This class manages the HUD (head-up-display) objects.
 * 
 * @author Roslan Amir
 * @version 1.0 - Jan 4, 2011
 */
public class HudManager {

	/**
     * 
     */
	private static final Logger logger = LoggerFactory.getLogger(Base.class);

	/**
	 * 
	 */
	public static final Map<String, Object> FONT_STYLES = new HashMap<String, Object>();

	/**
	 * 
	 */
	public static final Insets FRAME_INSETS = new Insets(3, 1, 5, 1);

	/**
	 * 
	 */
	public static final Insets MARGINS_ZERO = new Insets(0, 0, 0, 0);
	public static final Insets MARGINS_FOUR = new Insets(4, 0, 4, 0);

	/**
	 * 
	 */
	public static final Insets PADDING_ZERO = MARGINS_ZERO;
	public static final Insets PADDING_TWO = new Insets(2, 2, 2, 2);
	public static final Insets PADDING_FOUR = new Insets(-4, 0, 4, 0);
	public static final Insets PADDING_EIGHT = new Insets(-8, 0, 8, 0);
	public static final Insets PADDING_2000 = new Insets(2, 0, 0, 0);

	/**
	 * 
	 */
	public static final UIBorder SOLID_BORDER_TWO = new SolidBorder(2, 2, 2, 2);

	/*
	 * Static initialization block.
	 */
	static {
		/*
		 * Initialize the Font Styles
		 */
		FONT_STYLES.put(StyleConstants.KEY_BOLD, true);
		FONT_STYLES.put(StyleConstants.KEY_SIZE, 32);
		// FONT_STYLES.put(StyleConstants.KEY_ITALICS, true);
		// FONT_STYLES.put(StyleConstants.KEY_COLOR, ColorRGBA.WHITE); // does not work - still black
		// FONT_STYLES.put(StyleConstants.KEY_FAMILY, "Verdana"); // does not work - still default
	}

	/**
	 * The singleton instance of this class.
	 */
	private static HudManager instance;

	/**
	 * Reference to the single instance of the GameData class.
	 */
	private final GameData gameData = GameData.getInstance();

	/**
	 * Labels for displaying the information at the top of the screen.
	 */
	private UILabel empireLabel;
	private UILabel gameDateLabel;

	/**
	 * The panel to display information about an unexplored star.
	 */
	private StarInfoFrameUnexplored starInfoUnexplored;

	/**
	 * The panel to display information about an explored star.
	 */
	private StarInfoFrameExplored starInfoExplored;

	/**
	 * The panel to display information about an AI colony's star.
	 */
	private StarInfoFrameColonyAI starInfoColonyAI;

	/**
	 * The panel to display information about a player colony's star.
	 */
	private StarInfoFrameColonyPlayer starInfoColonyPlayer;

	/**
	 * The panel to display information about a newly explored star system.
	 */
	private StarInfoFrameExploreColonize starInfoExploring;

	/**
	 * The panel to display information about a colonizable star system.
	 */
	private StarInfoFrameExploreColonize starInfoColonizing;

	/**
	 * The panel to display the fact that s Star has been colonized.
	 */
	private StarInfoFrameColonized starInfoColonized;

	/**
	 * Holds the currently displayed instance of <code>StarInfoPanel</code>.
	 */
	private StarInfoFrameBase currentStarInfo;

	/**
	 * Holds the currently displayed instance of <code>FleetInfoFrame</code>.
	 */
	private FleetInfoFrame currentFleetInfo;

	/**
	 * Holds the currently displayed instance of Star Info Node.
	 */
	private StarInfoNodeBase currentStarInfoNode;

	/**
	 * The node to display information about an unexplored star.
	 */
	private StarInfoNodeUnexplored starInfoNodeUnexplored;

	/**
	 * The node to display information about an unexplored star.
	 */
	private StarInfoNodeExploredUninhabited starInfoNodeExploredUninhabited;

	/**
	 * The node to display information about an AI colony.
	 */
	private StarInfoNodeColonyAI starInfoNodeColonyAI;

	/**
	 * Private Constructor.
	 */
	private HudManager() {
	}

	/**
	 * Returns the singleton instance of this class.
	 * 
	 * @return the singleton instance of this class
	 */
	public static HudManager getInstance() {
		if (instance == null) {
			instance = new HudManager();
		}
		return instance;
	}

	/**
	 * Initialization.
	 * 
	 * @param camera - the camera to use
	 * @param Main.hud - the UIHud instance
	 */
	public void init() {
		/*
		 * Create the star information panels.
		 */
		starInfoUnexplored = new StarInfoFrameUnexplored();
		starInfoUnexplored.setHudXY(0, 0);
		starInfoUnexplored.setVisible(true);

		starInfoExplored = new StarInfoFrameExplored();
		starInfoExplored.setHudXY(0, 0);
		starInfoExplored.setVisible(true);

		starInfoColonyAI = new StarInfoFrameColonyAI();
		starInfoColonyAI.setHudXY(0, 0);
		starInfoColonyAI.setVisible(true);

		starInfoColonyPlayer = new StarInfoFrameColonyPlayer();
		starInfoColonyPlayer.setHudXY(0, 0);
		starInfoColonyPlayer.setVisible(true);

		starInfoExploring = new StarInfoFrameExploreColonize(false);
		starInfoExploring.setHudXY(0, 0);
		starInfoExploring.setVisible(true);

		starInfoColonizing = new StarInfoFrameExploreColonize(true);
		starInfoColonizing.setHudXY(0, 0);
		starInfoColonizing.setVisible(true);

		starInfoColonized = new StarInfoFrameColonized();
		// int w = starInfoColonized.getContentWidth();
		// int h = starInfoColonized.getContentHeight();
		// starInfoColonized.setHudXY((gameData.screenWidth - w) / 2, (gameData.screenHeight - h) / 2);
		starInfoColonized.setLocationRelativeTo(Main.camera);
		starInfoColonized.setVisible(true);

		currentStarInfo = starInfoColonyPlayer;

		/*
		 * Info node based HUD for stars
		 */
		starInfoNodeUnexplored = new StarInfoNodeUnexplored();
		starInfoNodeExploredUninhabited = new StarInfoNodeExploredUninhabited();
		starInfoNodeColonyAI = new StarInfoNodeColonyAI();
		currentStarInfoNode = null;

		/*
		 * Create the fleet information panel.
		 */
		currentFleetInfo = new FleetInfoFrame();

		/*
		 * Create the banner at the top of the screen
		 */
		createScreenBanner();
	}

	/**
	 * Create the labels of the screen banner.
	 */
	public void createScreenBanner() {
		empireLabel = new UILabel("Human Empire (Alexander)");
		empireLabel.setStyledText(true);
		empireLabel.setHudXY(0, gameData.screenHeight - empireLabel.getContentHeight());
		empireLabel.setAlignment(Alignment.LEFT);
		empireLabel.setForegroundColor(ColorRGBA.WHITE);
		empireLabel.setVisible(false);
		Main.hud.add(empireLabel);

		gameDateLabel = new UILabel("Game Date: 2400.0 Turn: 999");
		gameDateLabel.setStyledText(true);
		gameDateLabel.setHudXY(gameData.screenWidth - gameDateLabel.getContentWidth(), gameData.screenHeight - gameDateLabel.getContentHeight());
		gameDateLabel.setAlignment(Alignment.RIGHT);
		gameDateLabel.setForegroundColor(ColorRGBA.WHITE);
		gameDateLabel.setVisible(false);
		Main.hud.add(gameDateLabel);
	}

	/**
	 * Show the contents of the screen banner.
	 */
	public void showScreenBanner() {
		empireLabel.setText("[b]" + gameData.playerRace.getRaceName() + " Empire (" + gameData.playerLeaderName + ")[/b]");
		empireLabel.setVisible(true);
		gameDateLabel.setText("[b]Game Date: [c=#ff0]" + gameData.gameYear + '.' + gameData.gameMonth + "[/c] Turn: [c=#ff0]" + gameData.gameTurn + "[/c][/b]");
		gameDateLabel.setVisible(true);
	}

	/**
	 * Display the info on the current star.
	 */
	public void showStarInfo() {
		logger.info("Inside showStarInfo(): currentStarNode = " + gameData.currentStarNode);
		if (!Main.hud.hasChild(currentStarInfo)) {
			Main.hud.detachChild(currentFleetInfo);
			Main.hud.add(currentStarInfo);
		}
		Star star = gameData.currentStarNode.getStar();
		if (star.explored) {
			if (star.owner != null) {
				if (star.owner == gameData.playerRace) {
					showPlayerColonyInfo();
				} else {
					showAIColonyInfo();
				}
			} else {
				showExploredStarInfo();
			}
		} else {
			showUnexploredStarInfo();
		}
		logger.info("...leaving showStarInfo()");
	}

	/**
	 * Comment for method.
	 */
	private void showUnexploredStarInfo() {
		if (currentStarInfo != starInfoUnexplored) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.add(starInfoUnexplored);
			currentStarInfo = starInfoUnexplored;
		}
		starInfoUnexplored.update(gameData.currentStarNode);

		/*
		 * Info Node
		 */
		if (currentStarInfoNode != starInfoNodeUnexplored) {
			if (currentStarInfoNode != null) {
				currentStarInfoNode.removeFromParent();
			}
			currentStarInfoNode = starInfoNodeUnexplored;
		}
		currentStarInfoNode.update(gameData.currentStarNode);
	}

	/**
	 * Comment for method.
	 */
	private void showExploredStarInfo() {
		if (currentStarInfo != starInfoExplored) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.add(starInfoExplored);
			currentStarInfo = starInfoExplored;
		}
		starInfoExplored.update(gameData.currentStarNode);

		/*
		 * Info Node
		 */
		if (currentStarInfoNode != starInfoNodeExploredUninhabited) {
			if (currentStarInfoNode != null) {
				currentStarInfoNode.removeFromParent();
			}
			currentStarInfoNode = starInfoNodeExploredUninhabited;
		}
		currentStarInfoNode.update(gameData.currentStarNode);
	}

	/**
	 * Comment for method.
	 */
	private void showAIColonyInfo() {
		if (currentStarInfo != starInfoColonyAI) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.add(starInfoColonyAI);
			currentStarInfo = starInfoColonyAI;
		}
		starInfoColonyAI.update(gameData.currentStarNode);

		/*
		 * Info Node
		 */
		if (currentStarInfoNode != starInfoNodeColonyAI) {
			if (currentStarInfoNode != null) {
				currentStarInfoNode.removeFromParent();
			}
			currentStarInfoNode = starInfoNodeColonyAI;
		}
		currentStarInfoNode.update(gameData.currentStarNode);
	}

	/**
	 * Comment for method.
	 */
	private void showPlayerColonyInfo() {
		if (currentStarInfo != starInfoColonyPlayer) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.add(starInfoColonyPlayer);
			currentStarInfo = starInfoColonyPlayer;
		}
		starInfoColonyPlayer.update(gameData.currentStarNode);

		/*
		 * Info Node
		 */
		if (currentStarInfoNode != null) {
			currentStarInfoNode.removeFromParent();
			currentStarInfoNode = null;
		}
	}

	/**
	 * Comment for method.
	 * 
	 * @param starNode
	 */
	public void showExploringStarInfo(StarNode starNode) {
		if (currentStarInfo != starInfoExploring) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.add(starInfoExploring);
			currentStarInfo = starInfoExploring;
		}
		starInfoExploring.update(starNode);

		/*
		 * Info Node
		 */
		if (currentStarInfoNode != null) {
			currentStarInfoNode.removeFromParent();
			currentStarInfoNode = null;
		}
	}

	/**
	 * Comment for method.
	 * 
	 * @param starNode
	 */
	public void showColonizingStarInfo(StarNode starNode) {
		if (currentStarInfo != starInfoColonizing) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.add(starInfoColonizing);
			currentStarInfo = starInfoColonizing;
		}
		starInfoColonizing.update(starNode);

		/*
		 * Info Node
		 */
		if (currentStarInfoNode != null) {
			currentStarInfoNode.removeFromParent();
			currentStarInfoNode = null;
		}
	}

	/**
	 * Comment for method.
	 * 
	 * @param starNode
	 */
	public void showColonizedStarInfo(StarNode starNode) {
		if (!Main.hud.hasChild(starInfoColonized)) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.detachChild(currentFleetInfo);
			Main.hud.add(starInfoColonized);
		}
		starInfoColonized.update(starNode);

		/*
		 * Info Node
		 */
		if (currentStarInfoNode != null) {
			currentStarInfoNode.removeFromParent();
			currentStarInfoNode = null;
		}
	}

	/**
	 * Comment for method.
	 * 
	 * @param starNode
	 */
	public void hideColonizedStarInfo() {
		Main.hud.detachChild(starInfoColonized);
	}

	/**
	 * Comment for method.
	 */
	public void showFleetInfo() {
		logger.info("Inside showFleetInfo(): currentFleetNode = " + gameData.currentFleetNode);
		if (!Main.hud.hasChild(currentFleetInfo)) {
			Main.hud.detachChild(currentStarInfo);
			Main.hud.add(currentFleetInfo);
		}
		currentFleetInfo.init();
		logger.info("...leaving showFleetInfo()");
	}

	/**
	 * Update the currently selected fleet's info after a destination star is selected.
	 */
	public void updateFleetInfo() {
		if (Main.hud.hasChild(currentFleetInfo)) {
			currentFleetInfo.update();
		}
	}

	/**
	 * Comment for method.
	 * 
	 */
	public void updateDateAndTurn() {
		gameData.gameMonth++;
		if (gameData.gameMonth == 10) {
			gameData.gameYear++;
			gameData.gameMonth = 0;
		}
		gameData.gameTurn++;
		gameDateLabel.setText("[b]Game Date: [c=#ff0]" + gameData.gameYear + '.' + gameData.gameMonth + "[/c] Turn: [c=#ff0]" + gameData.gameTurn + "[/c][/b]");
	}

}
